package rpc
{
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import json.JSON;
	
	import mx.controls.Alert;
	
	public dynamic class RPC
	{
		public static var methods:RPC = new RPC();
		
		private static var methodParams:Object = new Object();
		
		public static function initialize():void
		{
		}
		
		public function RPC()
		{
			//makeMethods();
		}
		
		private var initialized:Boolean = false;
		
		private function makeMethods():void
		{
			makeRPCRequest
			(
				"ListServices",
				null,
				function(response:Object):void
				{
					for each(var serviceDescription:Object in response)
					{
						methodParams[serviceDescription.name] = serviceDescription.parameters;
						
						var method:Function
							= function (... args):void
							{
								var index:int = 0;
								var argsObject:Object = new Object();
								var name:String = serviceDescription.name;
								var parameters:Array = serviceDescription.parameters;
								
								for each(var pn:String in parameters)
								{
									if(index >= args.length || (args[index] is Function))
									{
										trace
										(
											"Function " + name + 
											" Takes in parameters " +
											parameters +
											" And optionally successHandler and failureHandler functions"
										);
										break;
									}
									args[pn] = args[index++];
								}
								
								var successHandler:Function
									= args[index] is Function ? args[index++] :  null;

								var failureHandler:Function
									= args[index] is Function ? args[index++] :  null;
								
								makeRPCRequest
								(
									name, argsObject,
									successHandler, failureHandler
								);
							};
						
						RPC.methods[serviceDescription.name] = method;
					}
				}
			);
		}
		
		private function defaultErrorHandler(service:String,code:String,message:String):void
		{
			Alert.show(code + ":" + message,"Error while invoking service " + service);
		}
		
		private function defaultSuccessHandler(response:Object):void
		{
			
		}
		
		public function makeRPCRequest
		(
			service:String,
			arguments:Object = null,
			onSucess:Function = null,
			onFailure:Function = null
		):void
		{
			
			if(onSucess == null)
			{
				onSucess = defaultSuccessHandler;
			}
			
			if(onFailure == null)
			{
				onFailure = defaultErrorHandler;
			}
			
			var request:URLRequest = new URLRequest
				(
					getServer() + 
					getAppName() +
					"/rpc?" + 
					"service=" + encodeURIComponent(service) +
					"&arguments=" +
					encodeURIComponent
					(
						JSON.encode(arguments != null ? arguments : new Object())
					) 
				);
				
			var loader:URLLoader = new URLLoader(request);
			
			loader.addEventListener
			(
				Event.COMPLETE,
				function(event:Event):void
				{
					var response:Object = JSON.decode(decodeURIComponent(loader.data));
					
					if(response.errorCode)
					{
						onFailure(service,response.errorCode,response.errorMessage);
					}
					else
					{
						onSucess(response);
					}
				}
			);
			
			loader.addEventListener
			(
				IOErrorEvent.IO_ERROR,
				function (event:IOErrorEvent):void
				{
					Alert.show(event.toString());
					onFailure
					(
						service,
						"Failed to connect to " + 
							RPC.methods.getServer() + 
							RPC.methods.getAppName(),
						event.toString()
					);
				}
			);
		}
		
		private static function getServer():String
		{
			return "http://localhost:8080/";
		}

		private static function getAppName():String
		{
			return "tomcat-adapter";
		}
	}
}
